/*
 * MainFrame.java
 *
 * Created on 2011-5-11, 21:31:07
 */
package banksimulator.ui;

import banksimulator.bank.AbstractAccount;
import banksimulator.bank.AbstractBank;
import banksimulator.bank.AccountFactory;
import banksimulator.bank.BankChangeEvent;
import banksimulator.bank.BankChangeListener;
import banksimulator.bank.BasicAccount;
import banksimulator.bank.FundsInsufficientException;
import banksimulator.bank.MemoryBank;
import banksimulator.bank.NoSuchAccountException;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.DecimalFormat;
import javax.swing.DefaultComboBoxModel;
import javax.swing.GroupLayout;
import javax.swing.GroupLayout.Alignment;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JFormattedTextField;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.LayoutStyle.ComponentPlacement;
import javax.swing.ListSelectionModel;
import javax.swing.SwingConstants;
import javax.swing.WindowConstants;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.text.DefaultFormatterFactory;
import javax.swing.text.NumberFormatter;

/**
 * 程序的主窗口。
 * @author Rajab
 */
public class MainFrame extends javax.swing.JFrame {

    //帐户工厂
    private AccountFactory accountFactory;
    //银行
    private AbstractBank bank;
    //当前选定的帐户
    private AbstractAccount currentAccount;
    //新建帐户对话框
    private JDialog newAccountDialog = null;

    /**
     * 设置当前选定的帐户。
     * @param account 当前帐户
     */
    private void setCurrentAccount(AbstractAccount account) {
        currentAccount = account;
    }

    /**
     * 获取当前模拟的银行。
     * @return 当前模拟的银行。
     */
    public AbstractBank getBank() {
        return bank;
    }

    /**
     * 根据指定的帐户工厂和银行，创建一个主窗口。
     * @param bank 储存帐户用的银行
     * @param accountFactory 帐户工厂
     */
    public MainFrame(AbstractBank bank, AccountFactory accountFactory) {
        this.bank = bank;
        this.accountFactory = accountFactory;
        init();
    }

    /**
     * 更新窗体显示的内容。主要包括accountInfoPanel
     */
    private void updateUI() {
        btnCommit.setEnabled(!isNullAccount());
        cbType.setSelectedIndex(0);
        accountInfoPanel.setAccount(currentAccount);
    }

    /** 初始化 */
    private void init() {
        //初始化显示的组件
        initComponents();
        setDefaultLookAndFeelDecorated(true);
        // 设置标题
        setTitle(bank.getName());
        //设置窗体位置
        setLocationRelativeTo(null);

        final AbstractBank fb = bank;

        try {
            //设置银行中的第一帐户为当前帐户
            setCurrentAccount(bank.getAccount(0));
            accountIDList.setSelectedIndex(0);
        } catch (IndexOutOfBoundsException ex) {
            //银行是空的
            setRemoveEnabled(false);
        } finally {
            updateUI();
        }

        //注册银行侦听器
        bank.addBankChangeListener(new BankChangeListener() {

            public void bankChanged(BankChangeEvent evt) {
                //没有帐户了
                if (fb.size() == 0) {
                    setRemoveEnabled(false);
                } else {
                    setRemoveEnabled(true);
                }
            }
        });
    }

    /**
     * 获取当前帐户是否是空帐户
     * @return 是否是空帐户
     */
    private boolean isNullAccount() {
        if (currentAccount == null) {
            return true;
        }
        return false;
    }

    /**
     * 设置是否允许删除帐户
     * @param enabled 是否允许删除帐户
     */
    private void setRemoveEnabled(boolean enabled) {
        btnRemove.setEnabled(enabled);
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        jScrollPane1 = new JScrollPane();
        accountIDList = new JList();
        btnSave = new JButton();
        btnCancel = new JButton();
        btnAddAccount = new JButton();
        jPanel1 = new JPanel();
        cbType = new JComboBox();
        btnCommit = new JButton();
        lblType = new JLabel();
        txtAmount = new JFormattedTextField();
        btnRemove = new JButton();
        accountInfoPanel = new AccountInfoPanel();

        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        setTitle("模拟银行");
        setMinimumSize(new Dimension(634, 284));

        accountIDList.setModel(new BankListModel(getBank()));
        accountIDList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        accountIDList.addListSelectionListener(new ListSelectionListener() {
            public void valueChanged(ListSelectionEvent evt) {
                accountIDListValueChanged(evt);
            }
        });
        jScrollPane1.setViewportView(accountIDList);

        btnSave.setText("保存");
        btnSave.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent evt) {
                btnSaveActionPerformed(evt);
            }
        });

        btnCancel.setText("取消");
        btnCancel.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent evt) {
                btnCancelActionPerformed(evt);
            }
        });

        btnAddAccount.setText("添加帐户");
        btnAddAccount.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent evt) {
                btnAddAccountActionPerformed(evt);
            }
        });

        cbType.setModel(new DefaultComboBoxModel(new String[] { "存钱", "取钱" }));
        cbType.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));

        btnCommit.setText("交易");
        btnCommit.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent evt) {
                btnCommitActionPerformed(evt);
            }
        });

        lblType.setText("操作：");

        txtAmount.setFormatterFactory(new DefaultFormatterFactory(new NumberFormatter(new DecimalFormat("¤#,##0.00"))));
        txtAmount.setValue(new Double(100.0));

        NumberFormatter fmt = (NumberFormatter) txtAmount.getFormatter();
        fmt.setValueClass(Double.class);
        GroupLayout jPanel1Layout = new GroupLayout(jPanel1);
        jPanel1.setLayout(jPanel1Layout);
        jPanel1Layout.setHorizontalGroup(
            jPanel1Layout.createParallelGroup(Alignment.LEADING)
            .addGroup(jPanel1Layout.createSequentialGroup()
                .addContainerGap()
                .addComponent(lblType, GroupLayout.PREFERRED_SIZE, 42, GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(ComponentPlacement.RELATED)
                .addComponent(cbType, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(ComponentPlacement.RELATED)
                .addComponent(txtAmount, GroupLayout.DEFAULT_SIZE, 308, Short.MAX_VALUE)
                .addPreferredGap(ComponentPlacement.RELATED)
                .addComponent(btnCommit)
                .addContainerGap())
        );
        jPanel1Layout.setVerticalGroup(
            jPanel1Layout.createParallelGroup(Alignment.LEADING)
            .addGroup(jPanel1Layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(jPanel1Layout.createParallelGroup(Alignment.BASELINE)
                    .addComponent(btnCommit)
                    .addComponent(txtAmount, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
                    .addComponent(cbType, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
                    .addComponent(lblType))
                .addContainerGap())
        );

        btnRemove.setText("删除帐户");
        btnRemove.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent evt) {
                btnRemoveActionPerformed(evt);
            }
        });

        GroupLayout layout = new GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(Alignment.LEADING)
                    .addGroup(layout.createSequentialGroup()
                        .addComponent(jScrollPane1, GroupLayout.PREFERRED_SIZE, 188, GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(ComponentPlacement.RELATED)
                        .addGroup(layout.createParallelGroup(Alignment.LEADING)
                            .addGroup(layout.createSequentialGroup()
                                .addGap(10, 10, 10)
                                .addComponent(accountInfoPanel, GroupLayout.DEFAULT_SIZE, 483, Short.MAX_VALUE))
                            .addComponent(jPanel1, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
                    .addGroup(layout.createSequentialGroup()
                        .addComponent(btnAddAccount)
                        .addGap(18, 18, 18)
                        .addComponent(btnRemove)
                        .addPreferredGap(ComponentPlacement.RELATED, 387, Short.MAX_VALUE)
                        .addComponent(btnSave)
                        .addPreferredGap(ComponentPlacement.RELATED)
                        .addComponent(btnCancel)))
                .addContainerGap())
        );

        layout.linkSize(SwingConstants.HORIZONTAL, new Component[] {btnAddAccount, btnRemove});

        layout.setVerticalGroup(
            layout.createParallelGroup(Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(Alignment.LEADING)
                    .addGroup(layout.createSequentialGroup()
                        .addGap(13, 13, 13)
                        .addComponent(jPanel1, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(ComponentPlacement.RELATED, 27, Short.MAX_VALUE)
                        .addComponent(accountInfoPanel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
                    .addComponent(jScrollPane1, GroupLayout.DEFAULT_SIZE, 314, Short.MAX_VALUE))
                .addGap(18, 18, 18)
                .addGroup(layout.createParallelGroup(Alignment.LEADING)
                    .addGroup(layout.createParallelGroup(Alignment.BASELINE)
                        .addComponent(btnAddAccount)
                        .addComponent(btnRemove))
                    .addGroup(layout.createParallelGroup(Alignment.BASELINE)
                        .addComponent(btnCancel)
                        .addComponent(btnSave)))
                .addContainerGap())
        );

        pack();
    }// </editor-fold>//GEN-END:initComponents

    // 按下保存按钮
    private void btnSaveActionPerformed(ActionEvent evt) {//GEN-FIRST:event_btnSaveActionPerformed
        accountInfoPanel.saveChanges();
    }//GEN-LAST:event_btnSaveActionPerformed

    private void btnCancelActionPerformed(ActionEvent evt) {//GEN-FIRST:event_btnCancelActionPerformed
//        if (bank.iterator().hasNext()) {
//            try {
//                bank.removeAccount(bank.iterator().next());
//            } catch (NoSuchAccountException ex) {
//                System.out.println(ex);
//            }
//        }
    }//GEN-LAST:event_btnCancelActionPerformed

    private void accountIDListValueChanged(ListSelectionEvent evt) {//GEN-FIRST:event_accountIDListValueChanged
        if (!evt.getValueIsAdjusting()) {
            return;
        }
        if (evt.getSource() instanceof JList) {
            JList list = (JList) evt.getSource();
            try {
                setCurrentAccount(bank.getAccount(list.getSelectedValue().toString()));
            } catch (NoSuchAccountException ex) {
                setCurrentAccount(null);
            } finally {
                updateUI();
            }

        }

    }//GEN-LAST:event_accountIDListValueChanged

    private void addAccount() {
        if (newAccountDialog == null) {
            newAccountDialog = new NewAccountDialog(this, true, accountFactory);
        }
        AbstractAccount ac = ((NewAccountDialog) newAccountDialog).getAccount();
        if (ac != null) {
            bank.addAccount(ac);
            setCurrentAccount(ac);
            accountIDList.setSelectedIndex(accountIDList.getModel().getSize() - 1);
            updateUI();
        }

    }
    //按下添加帐户
    private void btnAddAccountActionPerformed(ActionEvent evt) {//GEN-FIRST:event_btnAddAccountActionPerformed
        addAccount();
    }//GEN-LAST:event_btnAddAccountActionPerformed

    //更新帐户
    private void updateAccount() {
        if (isNullAccount()) {
            return;
        }
        Double amount = (Double) txtAmount.getValue();
        switch (cbType.getSelectedIndex()) {
            case 0:
                currentAccount.deposit(amount.doubleValue());
                break;
            case 1:
                try {
                    currentAccount.withdraw(amount.doubleValue());
                } catch (FundsInsufficientException ex) {
                    JOptionPane.showMessageDialog(this, ex.getMessage(),
                            "错误", JOptionPane.ERROR_MESSAGE);
                }
                break;
        }

    }
    //按下提交按钮
    private void btnCommitActionPerformed(ActionEvent evt) {//GEN-FIRST:event_btnCommitActionPerformed
        updateAccount();
}//GEN-LAST:event_btnCommitActionPerformed

    //删除帐户
    private void removeAccount() {
        if (isNullAccount()) {
            return;
        }
        int result = JOptionPane.showConfirmDialog(this, "你确定要删除该帐户吗?", "删除帐户", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
        switch (result) {
            case JOptionPane.YES_OPTION:
                try {
                    bank.removeAccount(currentAccount);
                    setCurrentAccount(null);
                    updateUI();
                } catch (NoSuchAccountException ex) {
                    System.out.printf("删除帐户%s失败\n", currentAccount.getAccountID());
                    return;
                }
                break;
            case JOptionPane.NO_OPTION:
                break;
        }
    }

    //删除按钮
    private void btnRemoveActionPerformed(ActionEvent evt) {//GEN-FIRST:event_btnRemoveActionPerformed
        removeAccount();
    }//GEN-LAST:event_btnRemoveActionPerformed

    /**
     * @param args the command line arguments
     */
    public static void main(String args[]) {
        java.awt.EventQueue.invokeLater(new Runnable() {

            public void run() {

                AbstractBank bank = new MemoryBank("中国银行");
                AccountFactory accountFactory = BasicAccount.factory;
                bank.addAccount(accountFactory.create("Kim", 1235.32));
                bank.addAccount(accountFactory.create("Lucy", 2345));
                bank.addAccount(accountFactory.create("Wang", 4512));
                bank.addAccount(accountFactory.create("Ma", 3500.23));
                bank.addAccount(accountFactory.create("Michael", 634));
                bank.addAccount(accountFactory.create("Jim", 734));
                bank.addAccount(accountFactory.create("Sion", 135456.3));
                bank.getAccount(0).deposit(2345.4);
                bank.getAccount(1).deposit(123.5);
                new MainFrame(bank, BasicAccount.factory).setVisible(true);
            }
        });
    }
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private JList accountIDList;
    private AccountInfoPanel accountInfoPanel;
    private JButton btnAddAccount;
    private JButton btnCancel;
    private JButton btnCommit;
    private JButton btnRemove;
    private JButton btnSave;
    private JComboBox cbType;
    private JPanel jPanel1;
    private JScrollPane jScrollPane1;
    private JLabel lblType;
    private JFormattedTextField txtAmount;
    // End of variables declaration//GEN-END:variables
}
